package com.lxf.clouduser.netty;

import com.alibaba.nacos.shaded.com.google.gson.Gson;
import com.lxf.clouduser.bean.*;
import com.lxf.clouduser.mapper.UserItemRepository;
import com.lxf.clouduser.mapper.UserMapper;
import com.lxf.clouduser.service.ChatService;
import com.lxf.clouduser.utils.AudioMsgUtils;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.websocket.OnMessage;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

/**
 * @author 罗兴发
 * @data 2025/4/3 14:58
 * @description：自定义Handler
 */
@Component
@ChannelHandler.Sharable
@Slf4j
public class WebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    @Resource
    ChatService chatService;
    @Resource
    UserMapper userMapper;
    @Resource
    private UserItemRepository userItemRepository;
    @Resource
    private AudioMsgUtils audioMsgUtils;
    /**
     * 一旦连接，第一个被执行
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        log.info("有新的客户端链接：[{}]", ctx.channel().id().asLongText());
        // 添加到channelGroup 通道组
        NettyConfig.getChannelGroup().add(ctx.channel());
    }

    /**
     * 读取数据
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        /**
         * 发送群消息ws
         */
        System.out.println("msg : " + msg.text());
        // 获取请求数据  解析json形式
        ReqModel model = new Gson().fromJson(msg.text(), ReqModel.class);

        // 获取用户ID,关联channel
        String userId = model.getUid();
        /**
         *
         * 聊天请求体
         *
         */
        RespModel respModel = new RespModel();
        //设置用户信息
        respModel.setUid(userId);
        respModel.setNickname(model.getNickname());

        //获取当前时间
        LocalDateTime now = LocalDateTime.now();
        String date = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        respModel.setDate(date);

        //bridge 初始值 要默认空值
        List<String> defaultList = new ArrayList<>();
        respModel.setBridge(defaultList);
        // 默认类型
        respModel.setType(RespType.OPERA.getNum());
        //判断请求类型
        ReqType type = ReqType.getTypeByNum(model.getType());
        switch (type) {
            case CONN:
                System.out.println(model.getNickname() + ": 用户上线了");
                //记录并返回在线用户列表 以及已经创建的群组列表
                //记录用户和通道的关联关系
                LocalData.channelUserUrl.put(userId, ctx.channel());

                NettyConfig.getChannelMap().put(userId, ctx.channel());
                // 将用户ID作为自定义属性加入到channel中，方便随时channel中获取用户ID
                AttributeKey<String> key = AttributeKey.valueOf("userId");
                ctx.channel().attr(key).setIfAbsent(userId);

                chatService.addUser(model, respModel);
                break;
            case CANCEL:
                System.out.println(model.getNickname() + ": 用户下线了");
                LocalData.channelUserUrl.remove(LocalData.channelUserUrl.get(model.getUid()));

                //删除语音通话
                audioMsgUtils.stopAudio();

                //更新用户在线
                userMapper.updateUserStatusByUserId(Integer.valueOf(userId),0);
                UserBean userBean1 = userMapper.selectByUserId(userId);
                //更新es中在线状态
                userItemRepository.save(userBean1);
                chatService.delUser(model, respModel);
                break;
            case ADD_GROUP:
                System.out.println(model.getNickname() + "用户创建了群组" + model.getGroupName());
                chatService.addGroup(model, respModel);
                break;
            case DEL_GROUP:
                System.out.println(model.getNickname() + "用户删除了群组" + model.getGroupName());
                chatService.delGroup(model, respModel);
                break;
            case JOIN_GROUP:
                System.out.println(model.getNickname() + "用户加入了群组" + model.getGroupName());
                chatService.joinGroup(model, respModel);
                break;
            case LEAVE_GROUP:
                System.out.println(model.getNickname() + "用户离开了群组" + model.getGroupName());
                chatService.leaveGroup(model, respModel);
                break;
            case SEND_NOTICE:
                System.out.println(model.getNickname() + "发送了系统公告" + model.getMsg());
                String uid = model.getUid();
                List<String> bridge = new ArrayList<>();
                //查询除却超级管理员之外的所有用户
                List<UserBean> list = userMapper.getUser(uid);
                for (UserBean user:list) {
                    bridge.clear();
                    bridge.add("");
                    bridge.add(""+user.getUserId());
                    model.setBridge(bridge);
                    //发送消息
                    chatService.sendPrivateMsg(model, respModel);
                }
                break;
            case SEND_MSG:
                //识别响应类型 消息类型是更改
                respModel.setType(RespType.MSG.getNum());

                //判断一对一消息还是一对多消息
                if (model.getBridge().size() == 0) {
                    //    一对多
                    chatService.sendGroupMsg(model, respModel);
                    if (null!=model.getIsAudio()&&model.getIsAudio()==1){
                        chatService.audioMsg(model,respModel);
                    }
                } else {
                    // 一对一
                    chatService.sendPrivateMsg(model, respModel);
                    if (null!=model.getIsAudio()&&model.getIsAudio()==1){
                        chatService.audioMsg(model,respModel);
                    }
                }
                break;
            default:
        }

        System.out.println(new Gson().toJson(respModel));
        if (respModel.getType() == RespType.OPERA.getNum()) {
            List<Channel> channels = LocalData.getAllChannels();
            notifyChannels(channels, respModel);
            return;
        }
        //    根据一对一 或者一对多的类型来找到接受通知的用户
        if (model.getBridge().size() > 0) {
            //  代表一对一,只需要通知自身和需要接受消息的用户
            String selfId = model.getBridge().get(0);
            Channel selfChannel = LocalData.channelUserUrl.get(selfId);

            //  接受信息的通道
            String otherId = model.getBridge().get(1);
            Channel otherChannel = LocalData.channelUserUrl.get(otherId);

            //  消息接收者有可能不在线，所以需要判空处理
            if (null!=otherChannel){
                List<Channel> channels = new ArrayList<>();
                channels.add(selfChannel);
                channels.add(otherChannel);
                notifyChannels(channels, respModel);
            }
            return;
        }
        //    一对多群组消息(能在群中发消息，证明群一定存在，群中一定有一个群主，故而不用判空处理)
        List<Channel> channels = new ArrayList<>();
        //    通过群id来找到群对象 获取用户列表 根据列表uid 获取对应的通道
        GroupBean groupModel = LocalData.getGroupById(model.getGroupId());
        for (UserBean userModel : groupModel.getUsers()) {
            Channel channel = LocalData.channelUserUrl.get(String.valueOf(userModel.getUserId()));
            channels.add(channel);
        }
        notifyChannels(channels, respModel);
    }

    private void notifyChannels(List<Channel> channels, RespModel respModel) {
        for (Channel channel : channels) {
            TextWebSocketFrame resp = new TextWebSocketFrame(new Gson().toJson(respModel));
            channel.writeAndFlush(resp);
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        //下线
        LocalData.channellist.remove(ctx.channel());
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //上线
        LocalData.channellist.add(ctx.channel());
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        log.info("用户下线了:{}", ctx.channel().id().asLongText());
        // 删除通道
        NettyConfig.getChannelGroup().remove(ctx.channel());
        LocalData.channelUserUrl.remove(ctx.channel());
        LocalData.channellist.remove(ctx.channel());
        removeUserId(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.info("异常：{}", cause.getMessage());
        // 删除通道
        NettyConfig.getChannelGroup().remove(ctx.channel());
        LocalData.channelUserUrl.remove(ctx.channel());
        removeUserId(ctx);
        ctx.close();
    }

    /**
     * 删除用户与channel的对应关系
     */
    private void removeUserId(ChannelHandlerContext ctx) {
        //删除私聊通道
        AttributeKey<String> key = AttributeKey.valueOf("userId");
        String userId = ctx.channel().attr(key).get();
        NettyConfig.getChannelMap().remove(userId);
        LocalData.channelUserUrl.remove(userId);
        UserBean userBean = userMapper.selectByUserId(userId);
        LocalData.userlist.remove(userBean);
    }
}
